#pragma once

#include <string>
#include <functional>
#include <cstring>
#include <fstream>

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>

#include "log.hpp"
#include "protocol.hpp"

namespace Server
{
    enum
    {
        USAGE_ERROR = 1,
        SOCKET_ERROR,
        BIND_ERROR,
        LISTEN_ERROR,
        OPEN_ERROR
    };

    using func_t = std::function<bool(const Request&, Response&)>;

    const uint16_t gport = 8080;
    const int gnacklog = 5;


    void TcpHeand(int sockfd, func_t func)
    {
        std::string inbuffer;
        while (true)
        {
#ifdef DEBUG
            std::cout << "debug-------------" << std::endl;
#endif
            // 1. 读数据
            std::string req_masg;
            if (!recvPackge(sockfd, inbuffer, &req_masg))
                return;
#ifdef DEBUG
            std::cout << "接收请求信息：" << req_masg << std::endl;
#endif
            std::string text;
            if (!deLenth(req_masg, &text))
                return;
#ifdef DEBUG
            std::cout << "去除报头的正文：" << text << std::endl;
#endif
            // 2. 反序列化
            Request req;
            if (!req.deserialize(text))
                return;
#ifdef DEBUG
            std::cout << "反序列化信息：" << req._x << req._op << req._y << std::endl;
#endif
            // 3. 业务处理
            Response resp;
            func(req, resp);
#ifdef DEBUG
            std::cout << "处理的数据信息：" << resp._exitcode << "  " << resp._result << std::endl;
#endif
            // 4. 序列化
            std::string resp_masg;
            resp.serialize(&resp_masg);
#ifdef DEBUG
            std::cout << "序列化信息：" << resp_masg << std::endl;
#endif
            // 5. 响应回客户端
            std::string send_string = enLenth(resp_masg);
            send(sockfd, send_string.c_str(), send_string.size(), 0);
#ifdef DEBUG
            std::cout << "发送消息：" << send_string << std::endl;
#endif
        }
    }

    class TcpServer
    {
    public:
        TcpServer(uint16_t port = gport)
            : _sock_listen(0), _port(port)
        {}

        void init()
        {
            // 1. 创建socket
            _sock_listen = socket(AF_INET, SOCK_STREAM, 0);
            if (_sock_listen == -1)
            {
                logMessage(FATAL, "create socket error");
                exit(SOCKET_ERROR);
            }
            logMessage(NORMAL, "create soket succes");

            // 2. bind 端口
            struct sockaddr_in local;
            memset(&local, 0, sizeof(local));
            local.sin_family = AF_INET;
            local.sin_port = htons(_port);
            local.sin_addr.s_addr = INADDR_ANY;

            if (bind(_sock_listen, (const struct sockaddr*)&local, sizeof(local)) < 0)
            {
                logMessage(FATAL, "socket bind error");
                exit(BIND_ERROR);
            }
            logMessage(NORMAL, "socket bind success");

            // 3. 设置socket 为 listen 状态
            if (listen(_sock_listen, gnacklog) < 0)
            {
                logMessage(FATAL, "socket listen error");
                exit(LISTEN_ERROR);
            }
            logMessage(NORMAL, "socket listen succes");


        }

        void start(func_t func)
        {
            signal(SIGCHLD, SIG_IGN);
            while (true)
            {
                // 4. 获取新连接
                struct sockaddr_in client;
                memset(&client, 0, sizeof(client));
                socklen_t clientlen = sizeof(client);
                int sockfd = accept(_sock_listen, (struct sockaddr *)&client, &clientlen);
                if (sockfd < 0)
                {
                    logMessage(ERROR, "socket accept error");
                    continue;
                }
                logMessage(NORMAL, "accept a new link succes, get new sock : %d", sockfd); //
                std::cout << "sock: " << sockfd << std::endl;

                // 多进程版本
                pid_t id = fork();
                if (id == 0)
                {
                    close(_sock_listen);
                    // if (fork() > 0)
                    //     exit(0);
                    // serviceIO(sockfd);
#ifdef DEBUG
                    std::cout << "创建子进程" << std::endl;
#endif
                    TcpHeand(sockfd, func);
                    close(sockfd);
                    exit(0);
                }
                close(sockfd);
            }
        }

    private:
        int _sock_listen;
        uint16_t _port;
    };
}

